#include <unistd.h>
#include <ext/stdio_filebuf.h>
#include <string>
#include <iostream>
#include <signal.h>
#include <sys/wait.h>

bool subprogram_exit=false;

void subprogram_exit_handler(int singo)
{
  std::cout<<"catch signal: "<<singo<<std::endl;
  pid_t pid;
  while((pid=waitpid(-1,nullptr,WNOHANG)>0))  //非堵塞
  {
    std::cout<<"Recycle Process "<<pid<<std::endl;
    subprogram_exit=true;
  }
}

int main()
{
  std::cout<<"Main Program Init"<<std::endl;
  //屏蔽信号
  sigset_t mset ,old;
  sigemptyset(&mset);
  sigaddset(&mset,SIGCHLD);
  sigprocmask(SIG_BLOCK,&mset,&old);

  int pipeSubIN[2];
  int pipeSubOUT[2];
  if(pipe(pipeSubIN)==-1)
  {
    std::cout<<"Can't open subprogram input pipe"<<std::endl;
    return -1;
  }
  if((pipe(pipeSubOUT)==-1))
  {
    std::cout<<"Can't open subprogram output pipe"<<std::endl;
    return -1;
  }
  pid_t pid=fork();
  if(pid<0) //error
  {
    std::cerr<<"Can't create subprogram"<<std::endl;
    return -1;
  }
  else if(pid==0) //subprogram
  {
    int returnValue=0;
    close(0); //close stdin
    returnValue=dup(pipeSubIN[0]);
    close(1); //close stdout
    returnValue=dup(pipeSubOUT[1]);
    if(execlp("../sub/sub","sub",nullptr)==-1)
      return -1;
  }

  //解除信号堵塞
  struct sigaction mact;
  mact.sa_flags=0;
  sigemptyset(&mact.sa_mask);
  mact.sa_handler=subprogram_exit_handler;
  sigaction(SIGCHLD,&mact,nullptr);
  sigprocmask(SIG_SETMASK,&old,nullptr);

  std::string data;
  __gnu_cxx::stdio_filebuf<char> programInputBuf(pipeSubIN[1],std::ios::out);
  __gnu_cxx::stdio_filebuf<char> programOutputBuf(pipeSubOUT[0],std::ios::in);
  std::ostream programInput(&programInputBuf); 
  std::istream programOutput(&programOutputBuf);
  while(true)
  {
    std::cout<<"MainProgram Input : ";
    std::cin>>data;
    programInput<<data<<std::endl;
    std::getline(programOutput,data);
    std::cout<<"SubProgram Output : "<<data<<std::endl;
    if(subprogram_exit)
    {
      std::cout<<"SubProgram Exit"<<std::endl;
      break;
    }
  }
  close(pipeSubIN[1]);
  close(pipeSubOUT[0]);
  std::cout<<"MainProgram Exit"<<std::endl;
}
